#include "EPollPoller.h"
#include "Channel.h"
#include "Logger.h"
#include "Timestamp.h"

// index_
const int kNew = -1;    // channel 未添加到poller中
const int kAdded = 1;   // channel 已添加到poller中
const int kDeleted = 2; // channel 从poller中移除

EPollPoller::EPollPoller(EventLoop *loop)
    : Poller(loop), epollfd_(epoll_create1(EPOLL_CLOEXEC)),
      events_(kInitEventListSize)
{
    if (epollfd_ < 0)
    {
        LOG_FATAL("epoll_create error:%d", errno);
    }
}
EPollPoller::~EPollPoller()
{
    close(epollfd_);
}

Timestamp EPollPoller::poll(int timeoutMs, ChannelList *activeChannels)
{
    LOG_INFO("fd total count:%d", channels_.size());
    int numEvents = epoll_wait(epollfd_, events_.data(),
                               static_cast<int>(events_.size()), timeoutMs);
    int saveErrno = errno;
    Timestamp now(Timestamp::now());
    if (numEvents > 0)
    {
        LOG_INFO("%d events happened", numEvents);
        fillActiveChannels(numEvents, activeChannels);
        if ((size_t)numEvents == events_.size())
        {
            events_.resize(events_.size() * 2);
        }
    }
    else if (numEvents == 0)
    {
        LOG_INFO("timeout!");
    }
    else
    {
        if (saveErrno != EINTR)
        {
            errno = saveErrno;
            LOG_ERROR("error");
        }
    }
    return now;
}

void EPollPoller::updateChannel(Channel *channel)
{
    const int index = channel->index();
    LOG_TRACE("");
    LOG_INFO("fd=%d events=%d index=%d", channel->fd(), channel->events(),
             channel->index());
    if (index == kNew || index == kDeleted)
    {
        if (index == kNew)
        {
            int fd = channel->fd();
            channels_[fd] = channel;
        }
        channel->setIndex(kAdded);
        update(EPOLL_CTL_ADD, channel);
    }
    else
    {
        if (channel->isNoneEvent())
        {
            LOG_TRACE("");
            update(EPOLL_CTL_DEL, channel);
            channel->setIndex(kDeleted);
        }
        else
        {
            update(EPOLL_CTL_MOD, channel);
        }
    }
}
// 从poller中删除channel
void EPollPoller::removeChannel(Channel *channel)
{

    int fd = channel->fd();
    channels_.erase(fd);
    int index = channel->index();

    if (index == kAdded)
    {
        LOG_TRACE("");
        update(EPOLL_CTL_DEL, channel);
    }
    channel->setIndex(kNew);
}

void EPollPoller::fillActiveChannels(int numEvents,
                                     ChannelList *activeChannels) const
{
    for (int i = 0; i < numEvents; i++)
    {
        Channel *channel = static_cast<Channel *>(events_[i].data.ptr);
        channel->setRevents(events_[i].events);
        activeChannels->push_back(
            channel); // eventloop拿到了poller返回给它的所有的有事件发生的channel的集合
    }
}

// epoll_ctl的封装
void EPollPoller::update(int operation, Channel *channel)
{
    struct epoll_event event;
    memset(&event, 0, sizeof(event));
    event.events = channel->events();
    event.data.ptr = channel;
    int fd = channel->fd();
    LOG_INFO("epoll_ctl operation:%d fd:%d", operation, fd);
    if (epoll_ctl(epollfd_, operation, fd, &event) < 0)
    {
        if (operation == EPOLL_CTL_DEL)
        {
            LOG_ERROR("epoll_ctl del error,fd:%d errno:%d", fd, errno);
        }
        else
        {
            LOG_FATAL("epoll_ctl add/mod error, errno:%d", errno);
        }
    }
}
